﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BingVis.SilverlightClient.Common;
using System.Threading;
using System.ComponentModel;

namespace BingVis.SilverlightClient.GoogleTransit
{
    public abstract class TransitLoaderBase<T> : ILoader<T>
    {
        protected IGTFSFile _originalFile;
        protected CSVParser _parser;
        private BackgroundWorker _loaderWorker;

        public event ItemLoadedEvent<T> ItemLoaded;
        public event DoneProcessingEvent DoneProcessing;

        public List<T> Items { get; protected set; }
        public bool Processing { get; protected set; }

        public TransitLoaderBase(IGTFSFile file)
        {
            _originalFile = file;
            _parser = new CSVParser(_originalFile);

            _loaderWorker = new BackgroundWorker();
            _loaderWorker.WorkerReportsProgress = false;
            _loaderWorker.WorkerSupportsCancellation = true;
            _loaderWorker.DoWork += new DoWorkEventHandler(_loaderWorker_DoWork);
            _loaderWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_loaderWorker_RunWorkerCompleted);
            Items = new List<T>();

            Processing = false;
        }

        void _loaderWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (e.Error.InnerException == null)
                    throw new Exception("Error during processing: " + e.Error.Message);

                var realError = e.Error.InnerException;
                while (e.Error.InnerException != null)
                    realError = e.Error.InnerException;

                throw realError;
            }

            int count = 0;
            if ( !e.Cancelled )
                count = (int)e.Result;

            OnDoneProcessing(count, e.Cancelled, null);
        }

        public void StopProcessing()
        {
            _loaderWorker.CancelAsync();
        }

        void _loaderWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;
            e.Cancel = false;
            int count = 0;
            foreach (var line in _parser.GetLines(_originalFile))
            {
                ProcessItem(line);
                count++;
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
            }

            e.Result = count;
        }

        public virtual void ProcessFile()
        {
            Processing = true;
            Items = new List<T>();

            _loaderWorker.RunWorkerAsync();
        }

        private void OnDoneProcessing(int numProcessed, bool hadError, object result)
        {
            Processing = false;

            if (DoneProcessing != null)
            {
                DoneProcessing.Invoke(this, new DoneProcessingEventArgs(numProcessed, hadError, result));
            }
        }

        public abstract void ProcessItem(ICSVLine line);

        protected void OnItemLoaded(T item)
        {
            if (ItemLoaded != null)
            {
                ItemLoaded.Invoke(this, new LoadedEventArgs<T>(item));
            }
        }

    }
}
